﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Microsoft.SharePoint;

namespace SPQueryToSql.ApplicationObjects.CAML
{
    internal abstract class BaseOperator
    {
        public FieldRef FieldRef;
        public Value Value;
        public FieldInfo FieldInfo;

        public virtual string CAMLElementName
        {
            get { return "Element"; }
        }

        public virtual string ToSql(Query query)
        {
            return ToSql(query, FieldInfo.InternalName);
            
        }

        public virtual string ToSql(Query query, string columnName)
        {
            var sql = new StringBuilder();
            if (FieldInfo.Type == SPFieldType.ContentTypeId)
            {
                if (Value != null)
                {
                    {
                        var ct = query.ContentTypes
                            .FirstOrDefault(x => x.Name.Equals(Value.Text, StringComparison.InvariantCultureIgnoreCase));
                        if (ct != null)
                        {
                            if (this is Eq)
                            {
                                sql.AppendFormat("[ContentTypeId] = {0}", ct.Id);
                            }
                            if (this is Neq)
                            {
                                sql.AppendFormat("[ContentTypeId] <> {0}", ct.Id);
                            }

                        }
                    }
                }
                if (this is In)
                {
                    var o = (In)this;
                    sql.Append("[ContentTypeId] IN (");
                    var cts = o.Values.Select(v => query.ContentTypes
                                                       .FirstOrDefault(
                                                           x =>
                                                           x.Name.Equals(v.Text,
                                                                         StringComparison.InvariantCultureIgnoreCase)))
                        .Select(c => c.Id)
                        .ToArray();
                    sql.Append(string.Join(",", cts));
                    sql.Append(")");
                }
            }
            return sql.ToString();
            // string.Format(SqlPredicateFormat, FieldInfo.InternalName, (Value == null ? string.Empty : Value.Text));
        }

        protected BaseOperator(XContainer element, IEnumerable<FieldInfo> listFields)
        {
            var fieldRef = element.Element("FieldRef");
            if (fieldRef != null)
                FieldRef = new FieldRef(fieldRef);
            var value = element.Element("Value");
            if (value != null)
                Value = new Value(value);
            FieldInfo = string.IsNullOrEmpty(FieldRef.Name)
                ? listFields.FirstOrDefault(x => x.Id == FieldRef.ID)
                : listFields.FirstOrDefault(x => x.InternalName.Equals(FieldRef.Name, StringComparison.InvariantCultureIgnoreCase));
        }

        protected BaseOperator()
        {
        }

        public override string ToString()
        {
            return ToString(0);
        }

        public virtual string ToString(int tabQnt)
        {
            var sb = new StringBuilder();
            const string tab = @"    ";
            for (var i = 0; i < tabQnt; i++) sb.Append(tab);
            sb.AppendFormat("<{0}>{1}{2}{3}", CAMLElementName, Environment.NewLine, FieldRef.ToString(tabQnt + 1),
                            (Value == null ? string.Empty : Value.ToString(tabQnt + 1)));
            for (var i = 0; i < tabQnt; i++) sb.Append(tab);
            sb.AppendFormat("</{0}>{1}", CAMLElementName, Environment.NewLine);
            return sb.ToString();
        }

        public List<FieldInfo> UsedFields
        {
            get
            {
                if (this is IOperatorContainer)
                {
                    return ((IOperatorContainer)this).Operators.SelectMany(x => x.UsedFields).ToList();
                }
                return new List<FieldInfo> { FieldInfo };
            }
        }
    }
}
